﻿using System;
using System.Linq;
using System.Xml.Linq;
using Lightray.Hattrick.ChppLib.EntityTypes;

namespace Lightray.Hattrick.ChppLib
{
    class HattrickXmlReader
    {
        private XElement _element;

        public HattrickXmlReader(XElement element)
        {
            _element = element;
        }

        public HattrickXmlReader(XDocument document)
        {
            _element = document.Root;
        }

        public int ReadNumber(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return 0;
                return Convert.ToInt32(value);
            }
            catch
            {
                return 0;
            }
        }

        public double ReadFloatNumber(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return 0;
                return Convert.ToDouble(value);
            }
            catch
            {
                return 0;
            }
        }

        public int ReadNumberOrDefault(string name, int defaultValue)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return defaultValue;
                return Convert.ToInt32(value);
            }
            catch
            {
                return defaultValue;
            }
        }

        public int ReadAttributeNumber(string name, string attribute)
        {
            try
            {
                string value;
                if (!getAttributeValue(ReadElement(name), attribute, out value))
                    return 0;
                return Convert.ToInt32(value);
            }
            catch
            {
                return 0;
            }
        }

        public bool ReadAttributeBoolean(string name, string attribute)
        {
            try
            {
                string value;
                if (!getAttributeValue(ReadElement(name), attribute, out value))
                    return false;

                value = value.ToLower();
                return value == "1" || value == "true";
            }
            catch
            {
                return false;
            }
        }

        public string ReadString(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return string.Empty;
                return value;
            }
            catch
            {
                return string.Empty;
            }
        }

        public MatchStatus ReadMatchStatus(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return MatchStatus.Finished;
                return (MatchStatus)Enum.Parse(typeof(MatchStatus), value, true);
            }
            catch
            {
                return MatchStatus.Finished;
            }
        }

        public SupportersMood ReadSupportersMood(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return SupportersMood.Unknown;
                return (SupportersMood)int.Parse(value);
            }
            catch
            {
                return SupportersMood.Unknown;
            }
        }

        public SponsorsMood ReadSponsorsMood(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return SponsorsMood.Unknown;
                return (SponsorsMood)int.Parse(value);
            }
            catch
            {
                return SponsorsMood.Unknown;
            }
        }

        public bool ReadBoolean(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return false;

                value = value.ToLower();
                return value == "1" || value == "true";
            }
            catch
            {
                return false;
            }
        }

        public SkillLevel ReadSkill(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return SkillLevel.Unknown;

                return (SkillLevel)Enum.Parse(typeof(SkillLevel), value, true);
            }
            catch
            {
                return SkillLevel.Unknown;
            }
        }

        public Agreeability ReadAgreeability(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Agreeability.PleasantGuy;
                return (Agreeability)Enum.Parse(typeof(Agreeability), value, true);
            }
            catch
            {
                return Agreeability.PleasantGuy;
            }
        }

        public HattrickAge ReadHattrickAge(string ageName, string ageDaysName)
        {
            try
            {
                return new HattrickAge(Convert.ToInt32(_element.Element(ageName).Value),
                                       Convert.ToInt32(_element.Element(ageDaysName).Value));
            }
            catch
            {
                return new HattrickAge(0, 0);
            }
        }

        public Aggressiveness ReadAggressiveness(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Aggressiveness.Calm;
                return (Aggressiveness)Enum.Parse(typeof(Aggressiveness), value, true);
            }
            catch
            {
                return Aggressiveness.Calm;
            }
        }

        public Honesty ReadHonesty(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Honesty.Honest;
                return (Honesty)Enum.Parse(typeof(Honesty), value, true);
            }
            catch
            {
                return Honesty.Honest;
            }
        }

        public Specialty ReadSpecialty(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Specialty.None;
                return (Specialty)Enum.Parse(typeof(Specialty), value, true);
            }
            catch
            {
                return Specialty.None;
            }
        }

        public Country ReadCountry(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Country.Sweden;
                return (Country)Enum.Parse(typeof(Country), value, true);
            }
            catch
            {
                return Country.Sweden;
            }
        }

        public DateTime ReadDate(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return DateTime.MinValue;
                return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:ss", null);
            }
            catch
            {
                return DateTime.MinValue;
            }
        }

        public TrophyType ReadTrophyType(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return TrophyType.Series;

                return (TrophyType)Enum.Parse(typeof(TrophyType), value, true);
            }
            catch
            {
                return TrophyType.Series;
            }
        }

        public Uri ReadUri(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return null;
                return new Uri(new Uri("http://www.hattrick.org/"), value);
            }
            catch
            {
                return null;
            }
        }

        public MatchType ReadMatchType(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return MatchType.RESERVED3;
                return (MatchType)Enum.Parse(typeof(MatchType), value, true);
            }
            catch
            {
                return MatchType.RESERVED3;
            }
        }

        public Weather ReadWeather(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Weather.Unknown;
                return (Weather)Enum.Parse(typeof(Weather), value, true);
            }
            catch
            {
                return Weather.Unknown;
            }
        }

        public Formation ReadFormation(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return Formation.F_4_4_2;

                value = "F_" + value.Replace("-", "_");
                return (Formation)Enum.Parse(typeof(Formation), value, true);
            }
            catch
            {
                return Formation.F_4_4_2;
            }
        }

        public TacticType ReadTacticType(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return TacticType.Normal;

                return (TacticType)Enum.Parse(typeof(TacticType), value, true);
            }
            catch
            {
                return TacticType.Normal;
            }
        }

        public TeamAttitude ReadTeamAttitude(string name)
        {
            try
            {
                string value;
                if (!getFirstDescendantValue(name, out value))
                    return TeamAttitude.Hidden;

                return (TeamAttitude)Enum.Parse(typeof(TeamAttitude), value, true);
            }
            catch
            {
                return TeamAttitude.Hidden;
            }
        }

        public XElement ReadElement(string name)
        {
            try
            {
                if (string.IsNullOrEmpty(name))
                    return _element;
                return _element.Descendants(name).FirstOrDefault();
            }
            catch
            {
                return null;
            }

        }

        private bool getFirstDescendantValue(string name, out string value)
        {
            XElement descendant = _element.Descendants(name).FirstOrDefault();
            if (descendant == null || string.IsNullOrEmpty(descendant.Value))
            {
                value = string.Empty;
                return false;
            }
          
            value = descendant.Value;
            return true;
        }

        private bool getAttributeValue(XElement element, string attribute, out string value)
        {
            XAttribute xattribute = element.Attribute(attribute);
            if (xattribute == null || string.IsNullOrEmpty(xattribute.Value))
            {
                value = string.Empty;
                return false;
            }

            value = xattribute.Value;
            return true;
        }

        private bool getFirstDescendantAttributeValue(string descendant, string attribute, out string value)
        {
            XElement xdescendant = _element.Descendants(descendant).FirstOrDefault();
            if (xdescendant == null)
            {
                value = string.Empty;
                return false;
            }

            return getAttributeValue(xdescendant, attribute, out value);
        }
    }
}
